package com.MyRibbonRuleConfig;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.*;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;


/**
 * @PROJECT_NAME: SpringCloud_AtGuiGu
 * @NAME: RandomLoadBalancer
 * @Author: lidongming
 * @DATE: 2022/2/10
 * @Desc:
 */

public class WriteMyRibbon implements ReactorServiceInstanceLoadBalancer {

    private static final Log log = LogFactory.getLog(WriteMyRibbon.class);

    private final String serviceId;
    private  static int []weight ;
    private  static int times ;
    private  static  ArrayList<ServiceInstance>list = new ArrayList<ServiceInstance>();
    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    /**
     * @param serviceInstanceListSupplierProvider a provider of
     * {@link ServiceInstanceListSupplier} that will be used to get available instances
     * @param serviceId id of the service for which to choose an instance
     */
    public WriteMyRibbon(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
                              String serviceId,int [] weight) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        WriteMyRibbon.weight = weight;


    }

    @SuppressWarnings("rawtypes")
    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
                .getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next()
                .map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
    }

    private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
                                                              List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }
//权重轮询
    private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }
//        测试自己手写是否成功

/**
 * 顺序执行的加权轮询算法
 * 缺点：权重=访问次数的时候，压力在一台服务器上 应该离散化
 */
//应该提取出来 在instance初始化的时候就直接加到list   如果断开连接或者增加服务器再操作list
        for (int i = 0; i < weight.length; i++) {

            for (int j = 0; j < weight[i]; j++) {
                list.add(instances.get(i));
            }
        }
        ServiceInstance instance = list.get(times%list.size());
        if (times>=Integer.MAX_VALUE)times = 0;
        times++;
        return new DefaultResponse(instance);
    }

}
